using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace MechWars
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Camera mCamera = new Camera();
        Camera closeCamera = new Camera();
        Matrix viewMatrix;
        Matrix projectionMatrix;
        Model thingy;
        Platform platformFloor;
        Platform platformCeil;
        int Height;
        int Width;
        SpriteFont font;
        List<Platform> platforms = new List<Platform>();
        Texture2D background;
        int timer;
        int platFormcount;
        int totalPlaforms;
        int plaformesRemoved;
        int updateCount;
        Player playerOne;
        Player playerTwo;
        float totalDrift;
        //old states
        MouseState oldMState;
        KeyboardState oldKBState;
        GamePadState oldGPStateOne;
        GamePadState oldGPStateTwo;

        Random rand = new Random();

        Vector3 cameraDrift = new Vector3(1,0,0);
        //end of old states

        //Values to edit cos you love them so
        const int PlatformTimer = 120;
        const float CameraDriftSpeed = 1;
        //the fun stuff stops here

        List<VertexPositionNormalTexture> vertexList = new List<VertexPositionNormalTexture>();
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferHeight = 1050;
            graphics.PreferredBackBufferWidth = 1680;
            graphics.IsFullScreen = true;
            graphics.ApplyChanges();
            Content.RootDirectory = "Content";
        }

        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here
            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);

            font = Content.Load<SpriteFont>("font");
            background = Content.Load<Texture2D>("StadumCrowd");
            Height = GraphicsDevice.Viewport.Height;
            Width = GraphicsDevice.Viewport.Width;
            mCamera.aspectRatio = (float)GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height;
            mCamera.postion = new Vector3(0, 0, -42);
            mCamera.focalPoint = new Vector3(0);
            mCamera.fov = 3.14f / 2;

            closeCamera.aspectRatio = (float)GraphicsDevice.Viewport.Width / (float)GraphicsDevice.Viewport.Height;
            closeCamera.postion = new Vector3(0, 0, -12);
            closeCamera.fov = 3.14f / 2;


            JMesh.staticGraphicsDevice = GraphicsDevice;
            Platform.preCalculate();
            platformFloor = new Platform(new Vector3(0, -40, 0),0);
            platformCeil = new Platform(new Vector3(0, 40, 0), 0);
            playerOne = new Player(new Vector2(0,2),false,Color.Red);
            playerTwo = new Player(new Vector2(0, -2), true, Color.Blue);
            closeCamera.focalPoint = new Vector3(playerOne.position, 0f);
            mCamera.update();
            // TODO: use this.Content to load your game content here
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {
            // TODO: Unload any non ContentManager content here
        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            // Allows the game to exit
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            MouseState MState = Mouse.GetState();
            KeyboardState KBState = Keyboard.GetState();
            GamePadState GPStateOne = GamePad.GetState(PlayerIndex.One);
            GamePadState GPStateTwo = GamePad.GetState(PlayerIndex.Two);
            // TODO: Add your update logic here

            updateCount++;
            totalDrift += -0.1f * CameraDriftSpeed;
            timer++;

            if (timer > PlatformTimer)
            {
                platFormcount++;
                totalPlaforms++;
                platFormcount++;
                totalPlaforms++;
                int length = rand.Next(1,4);
                int rander = (rand.Next(0, 12) - 6)*8;
            //    float sin = (float)Math.Sin(totalDrift * 2) * 35;
                platforms.Add(new Platform(mCamera.focalPoint - new Vector3(100 + length, rander, 0), length));
                platforms.Add(new Platform(mCamera.focalPoint - new Vector3(100 + length, -rander, 0), length));
                timer = 0;
            }
            for(int i = 0;i < platforms.Count();++i)
            {
                
                platforms[i].Update();
                if (mCamera.focalPoint.X - platforms[i].position.X < -100)
                {
                    platFormcount--;
                    plaformesRemoved++;
                    platforms.RemoveAt(i);
                }
            }
            mCamera.postion.X = totalDrift;
            mCamera.focalPoint.X = totalDrift;
            platformFloor.position.X = totalDrift;
            platformCeil.position.X = totalDrift;
            platformFloor.Update();
            platformCeil.Update();
            playerOne.Update(GPStateOne.ThumbSticks.Left.X);
            playerTwo.Update(GPStateTwo.ThumbSticks.Left.X);
            foreach (Platform plat in platforms.ToArray())
            {
                playerOne.applyPhiscalCorrections(Polygon.calPhysics(playerOne, plat.activePoly));
                playerTwo.applyPhiscalCorrections(Polygon.calPhysics(playerTwo, plat.activePoly));
            }

            playerOne.applyPhiscalCorrections(Polygon.calPhysics(playerOne,platformFloor.activePoly));
            playerTwo.applyPhiscalCorrections(Polygon.calPhysics(playerTwo, platformFloor.activePoly));

            playerOne.applyPhiscalCorrections(Polygon.calPhysics(playerOne, platformCeil.activePoly));
            playerTwo.applyPhiscalCorrections(Polygon.calPhysics(playerTwo, platformCeil.activePoly));

            if (GPStateOne.IsButtonDown(Buttons.A) && !oldGPStateOne.IsButtonDown(Buttons.A))
            {
                playerOne.Jump(false);
            }
            if (GPStateTwo.IsButtonDown(Buttons.A) && !oldGPStateTwo.IsButtonDown(Buttons.A))
            {
                playerTwo.Jump(false);
            }

            if (KBState.IsKeyDown(Keys.A))
            {
                closeCamera.focalPoint = new Vector3(playerOne.position, 0f);
                closeCamera.postion = new Vector3(playerOne.position.X - 6,playerOne.position.Y, -8f);
                closeCamera.update();
            }
            else if (KBState.IsKeyDown(Keys.B))
            {
                closeCamera.focalPoint = new Vector3(playerTwo.position, 0f);
                closeCamera.postion = new Vector3(playerTwo.position.X - 6, playerTwo.position.Y, -8f);
                closeCamera.update();
            }
            else
            {
                mCamera.update();
            }



            oldMState = MState;
            oldKBState = KBState;
            oldGPStateOne = GPStateOne;
            oldGPStateTwo = GPStateTwo;
            base.Update(gameTime);
        }

        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.Black);

            GraphicsDevice.BlendState = BlendState.Opaque;
            GraphicsDevice.DepthStencilState = DepthStencilState.Default;


            spriteBatch.Begin();

            spriteBatch.Draw(background, new Rectangle((int)(totalDrift * 5) % Width, 0, Width, Height), Color.White);
            spriteBatch.Draw(background, new Rectangle((int)(totalDrift * 5) % Width + Width, 0, Width, Height), Color.White);
            spriteBatch.End();

            JMesh.staticGraphicsDevice = GraphicsDevice;

            // TODO: Add your drawing code here
            foreach (Platform plat in platforms.ToArray())
            {
                plat.activeMesh.draw();
            }
            platformCeil.activeMesh.draw();
            platformFloor.activeMesh.draw();
            //foreach(ModelMesh mesh in thingy.Meshes)
            //{
              //  foreach(Effect effect in mesh.Effects)
              //  {
                    //effect.Vi
               // }
               /// mesh.Draw();
           // }

            playerOne.mesh.draw();
            playerTwo.mesh.draw();
            spriteBatch.Begin();
            spriteBatch.DrawString(font, "Updates: "+updateCount.ToString(), new Vector2(11,11), Color.Red);
            spriteBatch.DrawString(font, "Updates: "+updateCount.ToString(), new Vector2(10,10), Color.White);

            spriteBatch.DrawString(font, "Platforms: " + platFormcount.ToString(), new Vector2(11, 31), Color.Blue);
            spriteBatch.DrawString(font, "Platforms: " + platFormcount.ToString(), new Vector2(10, 30), Color.White);

            spriteBatch.DrawString(font, "Removed Platforms: " + plaformesRemoved.ToString(), new Vector2(11, 51), Color.Green);
            spriteBatch.DrawString(font, "Removed Platforms: " + plaformesRemoved.ToString(), new Vector2(10, 50), Color.White);

            spriteBatch.DrawString(font, "Total Platforms: " + totalPlaforms.ToString(), new Vector2(11, 71), Color.Yellow);
            spriteBatch.DrawString(font, "Total Platforms: " + totalPlaforms.ToString(), new Vector2(10, 70), Color.White);


            spriteBatch.DrawString(font, "Total Drift: " + totalDrift.ToString(), new Vector2(11, 91), Color.Purple);
            spriteBatch.DrawString(font, "Total Drift: " + totalDrift.ToString(), new Vector2(10, 90), Color.White);
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}
